﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
  
namespace Solidi
{
	public class DependencyContainer : IDependencyContainer, IDependencyRegistrar
	{
		private IDependencyRegistry _registry;
		private IDependencyResolver _resolver;
		private IDependencyLifetime _lifetime;
		
		public DependencyContainer()
			: this(DefaultRegistry(), DefaultResolver(), DefaultLifetime())
		{
		}

		public DependencyContainer(IDependencyRegistry registry, IDependencyResolver resolver, IDependencyLifetime lifetime)
		{
			_registry = registry;
			_resolver = resolver;
			_lifetime = lifetime;
		}

		public IDependencyLifetime Lifetime
		{
			get
			{
				return _lifetime;
			}
		}


		public IDependencyRegistry Registry
		{
			get
			{
				return _registry;
			}
		}

		public IDependencyResolver Resolver
		{
			get
			{
				return _resolver;
			}
		}

		private static IDependencyRegistry DefaultRegistry()
		{
			IDependencyRegistry registry = new DependencyRegistry();

			return registry;
		}

		private static IDependencyResolver DefaultResolver()
		{
			IDependencyResolver resolver = new DependencyResolver();
			
			resolver = new FuncDependencyResolver(resolver);
			resolver = new LazyDependencyResolver(resolver);
			resolver = new ListDependencyResolver(resolver);
			resolver = new AutoDependencyResolver(resolver);
			resolver = new CircularDependencyResolver(resolver);
			
			return resolver;
		}

		private static IDependencyLifetime DefaultLifetime()
		{
			IDependencyLifetime lifetime = new DependencyLifetime();

			return lifetime;
		}

		public object Resolve(IDependencyKey key)
		{
			object instance = Resolver.Resolve(new DependencyContext(this), key);

			if (instance == null)
			{
				throw new DependencyContainerException(String.Format("Could not find suitable constructor for {0}.", key));
			}

			return instance;
		}

		public void Dispose()
		{
			foreach (IDependency dependency in Registry.Dependencies)
			{
				dependency.Dispose();
			}
		}

		public IDependencyDecorator Register(IDependencyRegistration registration)
		{
			Dependency dependency = new Dependency(_registry, registration);

			_registry.Add(registration.Key, dependency);

			return dependency;
		}
	}
}
